package IntSet;

import java.util.Arrays;

public class IntSet {
    // 类型标识：1 = short, 2 = int, 3 = long
    public static final int INTSET_ENC_INT16 = 2; // short类型
    public static final int INTSET_ENC_INT32 = 4; // int类型
    public static final int INTSET_ENC_INT64 = 8; // long类型

    private Object data; // 用于存储数据的数组（根据类型不同，可能是short[]，int[]，long[]）
    private int length; // 集合中元素个数
    private int encoding; // 当前存储类型 1 = short, 2 = int, 3 = long

    public IntSet() {
        this.data = new short[0];
        this.length = 0;
        this.encoding = INTSET_ENC_INT16;
    }

    public int getEncoding() {
        return encoding;
    }

    // 插入
    public void insert(long value) {
        // IntSet中元素是唯一的
        if (find(value) != -1) {
            return;
        }

        // 如果当前类型的数组不能容纳该值，需要升级
        if ((encoding == INTSET_ENC_INT16 && (value < Short.MIN_VALUE || value > Short.MAX_VALUE)) ||
                (encoding == INTSET_ENC_INT32 && (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE))) {
            upgradeType(value);
        }

        // 根据当前类型放入不同的数据类型数组中
        switch (encoding) {
            case INTSET_ENC_INT16:
                short[] array = (short[]) data;
                array = Arrays.copyOf(array, length + 1);
                array[length] = (short) value;
                Arrays.sort(array); // IntSet中元素是有序的
                data = array;
                break;
            case INTSET_ENC_INT32:
                int[] array2 = (int[]) data;
                array2 = Arrays.copyOf(array2, length + 1);
                array2[length] = (int) value;
                Arrays.sort(array2);
                data = array2;
                break;
            case INTSET_ENC_INT64:
                long[] array3 = (long[]) data;
                array3 = Arrays.copyOf(array3, length + 1);
                array3[length] = value;
                Arrays.sort(array3);
                data = array3;
                break;
            default:
                throw new IllegalStateException("Unknown encoding");
        }

        length++;
    }

    // 升级类型
    private void upgradeType(long value) {
        if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
            // 从int16升级到int32
            if (encoding == INTSET_ENC_INT16) {
                int[] newData = new int[length + 1];
                short[] oldData = (short[]) data;
                for (int i = 0; i < length; i++) {
                    newData[i] = oldData[i];
                }
                data = newData;
                encoding = INTSET_ENC_INT32;
            }

            // 从int32升级到int64
            if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
                if (encoding == INTSET_ENC_INT32) {
                    long[] newData = new long[length + 1];
                    int[] oldData = (int[]) data;
                    for (int i = 0; i < length; i++) {
                        newData[i] = oldData[i];
                    }
                    data = newData;
                    encoding = INTSET_ENC_INT64;
                }
            }
        }

        System.out.println("触发升级，升级后的类型为:" + encoding);
    }

    // 二分查找查找元素
    public int find(long value) {
        int low = 0, high = length - 1;
        while (low <= high) {
            int mid = (low + high) / 2;
            switch (encoding) {
                case INTSET_ENC_INT16:
                    short[] array = (short[]) data;
                    if (value == array[mid]) return mid;
                    else if (value < array[mid]) high = mid - 1;
                    else low = mid + 1;
                    break;
                case INTSET_ENC_INT32:
                    int[] array2 = (int[]) data;
                    if (value == array2[mid]) return mid;
                    else if (value < array2[mid]) high = mid - 1;
                    else low = mid + 1;
                    break;
                case INTSET_ENC_INT64:
                    long[] array3 = (long[]) data;
                    if (value == array3[mid]) return mid;
                    else if (value < array3[mid]) high = mid - 1;
                    else low = mid + 1;
                    break;
                default:
                    throw new IllegalStateException("Unknown encoding");
            }
        }
        return -1;
    }

    // 获取IntSet中全部元素
    public Object getAllData() {
        return data;
    }
}
